/* eslint-disable @typescript-eslint/no-explicit-any */
import ThemeProvider from '@/design/ThemeProvider';
import BasicLayout from '@/layouts/BasicLayout';
import { getuuid } from '@/utils';
import { Alert, Button, Modal, ModalFuncProps, ModalProps } from 'antd';
import type { FC, ReactElement } from 'react';
import { cloneElement, useRef, useState } from 'react';
import ReactDOM from 'react-dom';
import type { DraggableEventHandler } from 'react-draggable';
import Draggable from 'react-draggable';

export interface BaseModalProps extends ModalProps {
  onSuccess?: (...arg: any) => void;
  onCancel: () => void;
}
export type ModalFC<T = Record<string, unknown>> = FC<T & BaseModalProps>;
/**
 * modal创建HOC，会根据传入的props等信息创建对应形式的modal
 * @param Component
 * @param options
 * @param config
 * @returns
 */
function WrapComponent(Component: ReactElement, options: any, config: any) {
  return cloneElement(Component, {
    ...options,
    ...config
  });
}
const modalMap = new Map<string, () => void>();
/**
 * function component模式下的modal创建hook，代理visible、close、render方法，并返回load、close方法进行调用
 *
 * const {load, close} = useModal(Component, anyProps);
 * @param Component 需要代理的modal组件订阅
 * @param options 需要预传入的props
 * @returns
 */
export function useModal<P extends BaseModalProps>(Component: FC<P>, options?: Partial<P>) {
  const div = document.createElement('div');
  // 保存modal上一次的props，
  let oldConfig = {};
  const id = getuuid();
  // 自定义render方法
  const render = (config: Omit<BaseModalProps, 'onCancel'> & { onCancel?: () => void }) => {
    // 浅合并 新旧config，保证在render时，只修改出现变化的config，保证其他config的数据不变
    // const realConfig = merge(oldConfig, config);
    const realConfig = { ...oldConfig, ...config };
    delete realConfig.destroyOnClose;
    ReactDOM.render(
      <ThemeProvider>
        <BasicLayout>
          {WrapComponent(<Component {...(options as P)} />, {}, realConfig)}
        </BasicLayout>
      </ThemeProvider>,
      div
    );
  };
  const close = () => {
    modalMap.delete(id);
    render({ visible: false });
    let destory = true;
    // 判断关闭后是否销毁modal
    if (options) {
      destory = !(options.destroyOnClose === false);
    }
    destory &&
      setTimeout(() => {
        oldConfig = {};
        ReactDOM.unmountComponentAtNode(div);
      }, 500);
  };

  const load = (props: Omit<P, 'onCancel'> & { onCancel?: () => void }) => {
    modalMap.set(id, close);
    render({
      ...props,
      visible: true,
      onCancel: () => {
        props && props.onCancel && props.onCancel();
        close();
      }
    });
  };
  return { close, load };
}
/**
 * 封装的modal组件，封装了拖动功能，其余功能与ant modal相同
 * @see https://ant.design/components/modal-cn/
 * @param props
 * @returns
 */
const BaseModal: typeof Modal = (props) => {
  const [bounds, setBounds] = useState({ left: 0, top: 0, bottom: 0, right: 0 });
  const [disabled, setDisabled] = useState(true);
  const draggleRef = useRef<HTMLDivElement>(null);

  const onStart: DraggableEventHandler = (event, uiData) => {
    const { clientWidth, clientHeight } = window?.document?.documentElement;
    const targetRect = draggleRef?.current?.getBoundingClientRect();
    if (targetRect) {
      setBounds({
        left: uiData?.x - targetRect?.left,
        right: clientWidth - (targetRect?.right - uiData?.x),
        top: uiData?.y - targetRect?.top,
        bottom: clientHeight - (targetRect?.bottom - uiData?.y)
      });
    }
  };
  return (
    <Modal
      width={800}
      keyboard={false}
      maskClosable={false}
      footer={[
        <Button
          key='ok'
          type={props.okType === 'danger' ? undefined : props.okType ?? 'primary'}
          danger={props.okType === 'danger'}
          onClick={props.onOk}
          loading={props.confirmLoading}
          {...props.okButtonProps}
        >
          {props.okText ?? '确定'}
        </Button>,
        <Button key='cancel' onClick={props.onCancel} {...props.cancelButtonProps}>
          {props.cancelText ?? '取消'}
        </Button>
      ]}
      {...props}
      title={
        <div
          style={{ width: '100%', cursor: 'move' }}
          onMouseOver={() => setDisabled(false)}
          onMouseOut={() => setDisabled(true)}
        >
          {props.title || <Alert type='warning' message='请补充弹窗标题' />}
        </div>
      }
      modalRender={(modal) => {
        return (
          <Draggable onStart={onStart} bounds={bounds} disabled={disabled}>
            <div ref={draggleRef}>{modal}</div>
          </Draggable>
        );
      }}
    />
  );
};
BaseModal.confirm = ({
  content,
  okText = '确定',
  cancelText = '取消',
  ...config
}: ModalFuncProps) =>
  Modal.confirm({
    content,
    okText,
    cancelText,
    ...config
  });
BaseModal.info = Modal.info;
BaseModal.success = Modal.success;
BaseModal.error = Modal.error;
BaseModal.warning = Modal.warning;
BaseModal.warn = Modal.warn;
BaseModal.destroyAll = () => {
  modalMap.forEach((close) => {
    close();
  });
  Modal.destroyAll();
};
BaseModal.useModal = Modal.useModal;
BaseModal.config = Modal.config;
export default BaseModal;
